
package squarePackage;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;

import Enumerations.Directions;
import Obstacle.Door;
import Obstacle.Wall;

/**
 * A class of TransparantSquares in a game, being the smallest unit of location, with own
 * temperature, humidity, slipperiness, inhabitability & borders.
 * 
 * @invar       the temperature has to be a valid temperature
 *              |isValidTemperature(this.getTemperature())
 * @invar       the temperature limits have to be valid
 *              |isValidMinMaxTemperature(this.getMIN_TEMPERATURE,this.getMAX_TEMPERATURE)
 * @invar       the humidity of the square has to be a valid percentage
 *              |isValidHumidity(this.getHumidity())
 * @invar		the square has minimum 1 wall with door, max 2 walls with door in opposite direction
 * 				|this.hasNumberOfDoors() =+ 1 || this.hasNumberOfDoors() == 2
 * 
 * @version 06/5/2011 11.27
 * @author An
 * 
 */


public class TransparantSquare extends SquareImp {
	
	/**
	 * A method to construct a transparent wall
	 * 
	 * @invar @see Square
	 * @invar numberOfWalls() == 1 || numberOfwalls() == 2
	 * @invar numberOfDoors() == numberOfWalls()
	 * 
	 * @param temperature
	 * @param humidity
	 * @param numberOfWalls
	 * @param direction
	 * 
	 * @throws IllegalArgumentException
	 * 
	 * @note if the number of walls equals two, the second wall will be placed in the opposite 
	 * direction of the first wall
	 * walls always have doors
	 */
	 public TransparantSquare(Double temperature, BigDecimal humidity, int numberOfWalls, Directions direction) throws IllegalArgumentException{
		 super(temperature ,humidity , getDirectionInArray(numberOfWalls,direction));	 
		 if (this.hasNumberOfDoors() <0 || this.hasNumberOfDoors()>2){
			 this.terminate();
		 }
	 }
	

	 /**
	  * A method to construct a standard transparent square with one or 2 walls in chosen directions
	  *
	  * @param numberOfWalls
	  * 		the number of walls you wish to set
	  * @param direction
	  * 		the direction in wich you wish to set the first wall
	  * 
	  * @post ...
	  * 	 |new.numberOfWalls() == numberOfWalls && new.numberOfDoors() == new.numberOfWalls();
	  * 
	  * @throws IllegalArgumentException
	  */
	 public TransparantSquare(int numberOfWalls, Directions direction) throws IllegalArgumentException{
		 this( (double) 0, new BigDecimal("0.50"),numberOfWalls, direction);		 
	 }
	 
	 /**
	  * A method to construct a standard transparent square with only one wall in chosen direction
	  * 
	  * @param direction
	  * 		the direction in which you wish to set the wall
	  * @post ...
	  *       |new.numberOfWalls() == 1 && new.numberOfDoors() == 1;
	  * 
	  * @throws IllegalArgumentException
	  */
	 public TransparantSquare(Directions direction) throws IllegalArgumentException{
		 this( (double) 0, new BigDecimal("0.50"), 1, direction);
	 }
	 
	 /**
	  * A method to construct a standard transparent wall
	  * 
	  * @post one wall in direction north
	  * 	  |...
	  * @post temperature equals zero
	  * 	  |...
	  * @post humidity equals zero point 5
	  * 	  |...
	  */
	 public TransparantSquare(){
		 this((double) 0, new BigDecimal("0.50"), 1, Directions.North);
	 }

	 /**
	  * A method to get an array of Directions
	  * 
	  * @param numberOfWalls
	  * 		the number of walls you wish
	  * @param direction
	  * 		the directions in which you wish the first wall
	  * @return Directions  []
	  * 		an array with both the fist direction as its opposite when
	  * 		when the number of walls is 2, else an array containing only
	  * 		the first direction
	  * 		
	  * @throws IlligalArgumentException if the number of directions is different
	  * 		from 1 or 2 or if the directions isn't valid
	  */
	private static Directions[] getDirectionInArray(int numberOfWalls,
			Directions direction) throws IllegalArgumentException {
		if(numberOfWalls == 1 && isValidDirections(numberOfWalls, direction)){
			Directions [] directions = {direction};
			return directions;			
		}
		else if (numberOfWalls == 2 && isValidDirections(numberOfWalls, direction)){
			Directions [] directions = {direction, Directions.getOppositeDirection(direction)};
			return directions;
		}
		else{
			throw new IllegalArgumentException();
		}
	}

	/**
	 * A method to check whether or not a direction is valid
	 * 
	 * @param numberOfWalls
	 * 			the number of walls you wish to check
	 * @param direction
	 * 			the direction in which you wish to set the first wall
	 * @return true if the direction is valid
	 * 			|!(direction == null);
	 * @return ...
	 * 			|!(direction == Directions.Floor)
	 * @return ...
	 * 			|!(numberOfWalls == 2 && direction == Directions.Ceiling)
	 */
	private static boolean isValidDirections(int numberOfWalls, Directions direction) {
		if (direction == null){
			return false;
		}
		else if (direction == Directions.Floor){
			return false;
		}
		else if (numberOfWalls == 2 && direction == Directions.Ceiling){
			return false;
		}
		else return true;
	}
	
	/**
	 * A method to check whether or not a border is valid for this square
	 * 
	 * @return true if this border is valid
	 * 			|...
	 *@note if the wall hasn't got a door, a door will be placed
	 */
	@Override
	public boolean isValidBorder(Directions direction, Wall wall) {
		if (!wall.hasDoor()){
			wall.setDoor(new Door());
		}
		if (this.hasNumberBorders() == 0){
			return true;
		}
		boolean oppositeOrEqual = false;
		ArrayList<Directions> directions = this.getBordersInDirections();
		Iterator<Directions> it = directions.iterator();
		while (it.hasNext()){
			Directions next = it.next();
			if (next != null){
				if(next == direction || next == Directions.getOppositeDirection(direction)){
					oppositeOrEqual = true;
				}
			}
		}
    	return (super.isValidBorder(direction, wall) && oppositeOrEqual);
		
    }
	
	/**
	 * A method to check whether or not a border of a neighbour is valid to replace
	 * the border of this square
	 * 
	 * @param direction
	 * 			the direction in which you wish to replace the border
	 * @param wall
	 * 			the wall you wish to set as border
	 * @return true if this neighbour's border is valid to set as border for this square
	 * 		   | ...
	 * 
	 */
	@Override
	public boolean isValidNeighbourBorder(Directions direction, Wall wall) {
		if (!wall.hasDoor()){
			return false;
		}
		else {
		boolean oppositeOrEqual = false;
		ArrayList<Directions> directions = this.getBordersInDirections();
		Iterator<Directions> it = directions.iterator();
		while (it.hasNext()){
			Directions next = it.next();
			if (next != null){
				if(next == direction || next == Directions.getOppositeDirection(direction)){
					oppositeOrEqual = true;
				}
			}
		}
    	return (super.isValidBorder(direction, wall) && oppositeOrEqual);
		
    }
	}
}
